// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CommonUserTypes.h"
/**
 * A game viewport (FViewport) is a high-level abstract interface for the
 * platform specific rendering, audio, and input subsystems.
 * GameViewportClient is the engine's interface to a game viewport.
 * Exactly one GameViewportClient is created for each instance of the game.  The
 * only case (so far) where you might have a single instance of Engine, but
 * multiple instances of the game (and thus multiple GameViewportClients) is when
 * you have more than one PIE window running.
 *
 * Responsibilities:
 * propagating input events to the global interactions list
 *
 * @see UGameViewportClient
 */

/**
 * 对于平台的特定渲染，音频和输入系统来说，游戏视口(FViewport)是高级的抽象接口。
 * GameViewportClient是引擎与游戏视口之间的接口。
 * 准确地是每个游戏实例创造一个GameViewportClient。
 * 仅有一种情况，例如你也许只有单个引擎实例，但是多个游戏实例(并且这时有多个GameViewportClients)当你有多个PIE窗口运行时。
 *
 * 职责:
 * 增加输入事件到全局交互列表中。
 */
#include "Engine/GameViewportClient.h"
/**
 * Wrapper for opaque type FUniqueNetId
 *
 * Makes sure that the opaque aspects of FUniqueNetId are properly handled/serialized 
 * over network RPC and actor replication
 */

/**
 * 封装对于FUniqueNetId来说的不透明类型。
 *
 * 确保FUniqueNetId的不透明方面在网络RPC和Actor复制过程中得到妥善处理和序列化。
 */
#include "GameFramework/OnlineReplStructs.h"
/**
 * UGameInstanceSubsystem
 * Base class for auto instanced and initialized systems that share the lifetime of the game instance
 */

/**
 * UGameInstanceSubsystem
 * 自动实例和初始化系统的基类，并且也是共享游戏声明周期的基类。
 */
#include "Subsystems/GameInstanceSubsystem.h"

#include "GameplayTagContainer.h"
#include "Interfaces/OnlineIdentityInterface.h"
#include "OnlineError.h"
/**
 * FWeakObjectPtr is a weak pointer to a UObject. 
 * It can return nullptr later if the object is garbage collected.
 * It has no impact on if the object is garbage collected or not.
 * It can't be directly used across a network.
 *
 * Most often it is used when you explicitly do NOT want to prevent something from being garbage collected.
 */

/**
 * FWeakObjectPtr是一个UObject的弱指针。
 * 如果对象被GC回收之后能够返回FWeakObjectPtr。
 * 对象是否被GC回收对于FWeakObjectPtr来说没有影响。
 * FWeakObjectPtr不能直接地被用于网络方面。
 *
 * FWeakObjectPtr经常被用于当你明确地不想要阻止GC回收时的情况。
 */
#include "UObject/WeakObjectPtr.h"
#include "CommonUserSubsystem.generated.h"

/**
 * Holds a gameplay tag that was registered during static construction of the module, and will
 * be unregistered when the module unloads.  Each registration is based on the native tag pointer
 * so even if two modules register the same tag and one is unloaded, the tag will still be registered
 * by the other one.
 */

/**
 * 在这模块静态构造期间拥有被注册地GT，并且在模块被卸载时GT也会被卸载。
 * 每个注册是基于原始的Tag指针，因此如果两个模块注册相同的Tag并且其中一个卸载，这个Tag将仍会注册在另一个上面。
 */
class FNativeGameplayTag;
/**
 *	OnlineSubsystem - Series of interfaces to support communicating with various web/platform layer services
 */

/**
 * OnlineSubsystem - 支持各种Web/平台层服务沟通地一系列接口。
 */
class IOnlineSubsystem;

/** List of tags used by the common user subsystem */

/** 被用于CommonUserSubsystem的标签列表。 */
struct COMMONUSER_API FCommonUserTags
{
	// General severity levels and specific system messages

	// 生成严重等级和特定地系统消息。
	static FNativeGameplayTag SystemMessage_Error;	// SystemMessage.Error
	static FNativeGameplayTag SystemMessage_Warning; // SystemMessage.Warning
	static FNativeGameplayTag SystemMessage_Display; // SystemMessage.Display

	/** All attempts to initialize a player failed, user has to do something before trying again */

	/** 所有尝试去初始化一个玩家都失败，用户再次尝试之前不得不去做些事情。 */
	static FNativeGameplayTag SystemMessage_Error_InitializeLocalPlayerFailed; // SystemMessage.Error.InitializeLocalPlayerFailed


	// Platform trait tags, it is expected that the game instance or other system calls SetTraitTags with these tags for the appropriate platform

	// 平台特征标签，它是被预料地，游戏实例或其他系统调用对于适当地平台的Tags的SetTraitTags方法。

	/** This tag means it is a console platform that directly maps controller IDs to different system users. If false, the same user can have multiple controllers */

	/** 这个标签意味着，此平台是能直接映射控制器IDs到不同系统用户主机平台。如果为false，相同用户能有多个控制器。 */
	static FNativeGameplayTag Platform_Trait_RequiresStrictControllerMapping; // Platform.Trait.RequiresStrictControllerMapping

	/** This tag means the platform has a single online user and all players use index 0 */

	/** 这个标签意味着，此平台有单个在线用户并且所有玩家索引是0。 */
	static FNativeGameplayTag Platform_Trait_SingleOnlineUser; // Platform.Trait.SingleOnlineUser
};

/** Logical representation of an individual user, one of these will exist for all initialized local players */

/** 一个单独用户的逻辑表现，对于所有的初始化的本地玩家都存在一个逻辑表现。 */
UCLASS(BlueprintType)
class COMMONUSER_API UCommonUserInfo : public UObject
{
	GENERATED_BODY()

public:
	/** Primary controller input device for this user, they could also have additional secondary devices */

	/** 此用户的主要控制器输入设备，该用户也能有额外的次要设备。 */

	/**
	 * Represents a single input device such as a gamepad, keyboard, or mouse.
	 *
	 * Has a globally unique identifier that is assigned by the IPlatformInputDeviceMapper
	 */

	/**
	 * 代表单个输入设备，例如游戏手柄、键盘或鼠标。
	 *
	 * 有一个被IPlatformInputDeviceMapper分配的全局唯一标识符。
	 */
	UPROPERTY(BlueprintReadOnly, Category = UserInfo)
	FInputDeviceId PrimaryInputDevice;

	/** Specifies the logical user on the local platform, guest users will point to the primary user */

	/** 指定本地平台的逻辑用户，访客用户将会指向主要用户。 */

	/** 
	 * Handle that defines a local user on this platform.
	 * This used to be just a typedef int32 that was used interchangeably as ControllerId and LocalUserIndex.
	 * Moving forward these will be allocated by the platform application layer.
	 */

	/**
	 * 在平台上定义的本地用户的句柄。
	 * 这过去仅仅是一个int32的类型别名，它曾被交替用作ControllerId和LocalUserIndex。
	 * 今后，这些(FPlatformUserId等)将由平台应用层来进行分配。  
	 */
	UPROPERTY(BlueprintReadOnly, Category = UserInfo)
	FPlatformUserId PlatformUser;
	
	/** If this user is assigned a LocalPlayer, this will match the index in the GameInstance localplayers array once it is fully created */

	/** 如果这个用户被分配一个本地玩家，一旦游戏实例完全创建，这将游戏实例本地玩家数组中分配索引。 */
	UPROPERTY(BlueprintReadOnly, Category = UserInfo)
	int32 LocalPlayerIndex = -1;

	/** If true, this user is allowed to be a guest */

	/** 如果为true，这个用户被允许成为访客。 */
	UPROPERTY(BlueprintReadOnly, Category = UserInfo)
	bool bCanBeGuest = false;

	/** If true, this is a guest user attached to primary user 0 */

	/** 如果为true，这个访客将会与主玩家0关联。 */
	UPROPERTY(BlueprintReadOnly, Category = UserInfo)
	bool bIsGuest = false;

	/** Overall state of the user's initialization process */

	/** 用户初始化进程的总体状态。 */
	UPROPERTY(BlueprintReadOnly, Category = UserInfo)
	ECommonUserInitializationState InitializationState = ECommonUserInitializationState::Invalid;

	/** Returns true if this user has successfully logged in */

	/** 如果用户已经成功登录，则返回true。 */
	UFUNCTION(BlueprintCallable, Category = UserInfo)
	bool IsLoggedIn() const;

	/** Returns true if this user is in the middle of logging in */

	/** 如果用户处于登录中，则返回true。 */
	UFUNCTION(BlueprintCallable, Category = UserInfo)
	bool IsDoingLogin() const;

	/** Returns the most recently queries result for a specific privilege, will return unknown if never queried */

	/** 针对一个特定权限返回最近的参数结果，如果没有请求则返回unknown。 */
	UFUNCTION(BlueprintCallable, Category = UserInfo)
	ECommonUserPrivilegeResult GetCachedPrivilegeResult(ECommonUserPrivilege Privilege, ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;

	/** Ask about the general availability of a feature, this combines cached results with state */

	/** 请求一个功能的普遍可用性，这会将缓存结果和当前状态相结合。 */
	UFUNCTION(BlueprintCallable, Category = UserInfo)
	ECommonUserAvailability GetPrivilegeAvailability(ECommonUserPrivilege Privilege) const;

	/** Returns the net id for the given context */

	/** 返回给定上下文内容的网络ID。 */
	UFUNCTION(BlueprintCallable, Category = UserInfo)
	FUniqueNetIdRepl GetNetId(ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;

	/** Returns the user's human readable nickname */

	/** 返回人类可阅读的昵称。 */
	UFUNCTION(BlueprintCallable, Category = UserInfo)
	FString GetNickname() const;

	/** Returns an internal debug string for this player */

	/** 返回该玩家的网络调试字符串。 */
	UFUNCTION(BlueprintCallable, Category = UserInfo)
	FString GetDebugString() const;

	/** Accessor for platform user id */

	/** 此平台用户ID的访问器。 */
	FPlatformUserId GetPlatformUserId() const;

	/** Gets the platform user index for older functions expecting an integer */

	/** 获取平台用户索引，针对旧函数期望的是整型。 */
	int32 GetPlatformUserIndex() const;

	// Internal data, only intended to be accessed by online subsystems

	/** 内部数据，仅旨在去连接在线系统。 */
	/** Cached data for each online system */

	/** 每次在线子系统的缓存数据。 */
	struct FCachedData
	{
		/** Cached net id per system */

		/** 缓存每个系统的网络ID。 */
		FUniqueNetIdRepl CachedNetId;

		/** Cached values of various user privileges */

		/** 缓存各种用户的权限值。 */
		TMap<ECommonUserPrivilege, ECommonUserPrivilegeResult> CachedPrivileges;
	};

	/** Per context cache, game will always exist but others may not */

	/** 每个上下文的缓存，Game在线模式经常存在但是其他的可能不存在。 */
	TMap<ECommonUserOnlineContext, FCachedData> CachedDataMap;
	
	/** Looks up cached data using resolution rules */

	/** 查看缓存数据用于解决规则。 */
	FCachedData* GetCachedData(ECommonUserOnlineContext Context);
	const FCachedData* GetCachedData(ECommonUserOnlineContext Context) const;

	/** Updates cached privilege results, will propagate to game if needed */

	/** 更新缓存的权限结果，如果需要将会增值到Game中。 */
	void UpdateCachedPrivilegeResult(ECommonUserPrivilege Privilege, ECommonUserPrivilegeResult Result, ECommonUserOnlineContext Context);

	/** Updates cached privilege results, will propagate to game if needed */

	/** NOTE: (不确定注释是否对)更新缓存的网络ID，如果需要将会增值到游戏中。 */
	void UpdateCachedNetId(const FUniqueNetIdRepl& NewId, ECommonUserOnlineContext Context);

	/** Return the subsystem this is owned by */

	/** 返回被拥有的子系统。 */
	class UCommonUserSubsystem* GetSubsystem() const;
};


/** Delegates when initialization processes succeed or fail */

/** 当初始化进程成功或失败时的代理。 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FiveParams(FCommonUserOnInitializeCompleteMulticast, const UCommonUserInfo*, UserInfo, bool, bSuccess, FText, Error, ECommonUserPrivilege, RequestedPrivilege, ECommonUserOnlineContext, OnlineContext);
DECLARE_DYNAMIC_DELEGATE_FiveParams(FCommonUserOnInitializeComplete, const UCommonUserInfo*, UserInfo, bool, bSuccess, FText, Error, ECommonUserPrivilege, RequestedPrivilege, ECommonUserOnlineContext, OnlineContext);

/** Delegate when a system error message is sent, the game can choose to display it to the user using the type tag */

/** 当系统错误日志被发送时，这游戏能够选择去展示错误信息，去使用类型标签的代理。 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FCommonUserHandleSystemMessageDelegate, FGameplayTag, MessageType, FText, TitleText, FText, BodyText);

/** Delegate when a privilege changes, this can be bound to see if online status/etc changes during gameplay */

/** 当权限发生变化时的代理，这可以被绑定(到相关逻辑上)，以便在游戏进行过程中查看在线状态等方面是否发生了变化。 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FCommonUserAvailabilityChangedDelegate, const UCommonUserInfo*, UserInfo, ECommonUserPrivilege, Privilege, ECommonUserAvailability, OldAvailability, ECommonUserAvailability, NewAvailability);


/** Parameter struct for initialize functions, this would normally be filled in by wrapper functions like async nodes */

/** 对于初始化函数的参数结构体，它通常是被像异步节点之类的包装函数填充的。 */
USTRUCT(BlueprintType)
struct COMMONUSER_API FCommonUserInitializeParams
{
	GENERATED_BODY()
	
	/** What local player index to use, can specify one above current if can create player is enabled */

	/** 本地玩家索引使用什么？如果创造玩家功能是可用的，能够指定一个高于当前索引值的索引。 */
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Default)
	int32 LocalPlayerIndex = 0;

	/** Deprecated method of selecting platform user and input device */

	/** 废弃的选择平台用户和输入设备的方式。 */
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Default)
	int32 ControllerId = -1;

	/** Primary controller input device for this user, they could also have additional secondary devices */

	/** 此用户的主控制器输入设备，它们也有额外的副设备。 */
	UPROPERTY(BlueprintReadOnly, Category = UserInfo)
	FInputDeviceId PrimaryInputDevice;

	/** Specifies the logical user on the local platform */

	/** 本地平台的特定逻辑用户。 */
	UPROPERTY(BlueprintReadOnly, Category = UserInfo)
	FPlatformUserId PlatformUser;
	
	/** Generally either CanPlay or CanPlayOnline, specifies what level of privilege is required */

	/** 通常来说要么是CanPlay或CanPlayOnline，被请求的特定地权限等级是哪个。 */
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Default)
	ECommonUserPrivilege RequestedPrivilege = ECommonUserPrivilege::CanPlay;

	/** What specific online context to log in to, game means to login to all relevant ones */

	/** 登录的特定的在线上下文是那个，Game在线模式意味着与所有的在线模式相关联。 */
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Default)
	ECommonUserOnlineContext OnlineContext = ECommonUserOnlineContext::Game;

	/** True if this is allowed to create a new local player for initial login */

	/** 如果为True，则意味着初始登录是允许去创建新的本地玩家。 */
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Default)
	bool bCanCreateNewLocalPlayer = false;

	/** True if this player can be a guest user without an actual online presence */

	/** 如果为True，此玩家是一个访客而不是实际的在线状态。 */
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Default)
	bool bCanUseGuestLogin = false;

	/** True if we should not show login errors, the game will be responsible for displaying them */

	/** 如果为True，我们不应该展示登录错误，此游戏将会有义务去展示他们。 */
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Default)
	bool bSuppressLoginErrors = false;

	/** If bound, call this dynamic delegate at completion of login */

	/** 如果绑定，将会在登录完成时调用动态代理。 */
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Default)
	FCommonUserOnInitializeComplete OnUserInitializeComplete;
};

/**
 * Game subsystem that handles queries and changes to user identity and login status.
 * One subsystem is created for each game instance and can be accessed from blueprints or C++ code.
 * If a game-specific subclass exists, this base subsystem will not be created.
 */

/**
 * 处理用户认证和登录状态的查询和改变的游戏子系统。
 * 一个子系统被每个游戏实例创造并且能够被蓝图和C++关联。
 * 如果游戏特定子类存在，这个基类将不会被创建。
 * NOTE: https://blog.csdn.net/ChaoChao66666/article/details/136051564
 */
UCLASS(BlueprintType, Config=Game)
class COMMONUSER_API UCommonUserSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()

public:
	UCommonUserSubsystem() { }
	/** 下面三个函数数据基本函数了，针对继承自游戏实例的类的基本函数。 */
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;
	virtual void Deinitialize() override;
	virtual bool ShouldCreateSubsystem(UObject* Outer) const override;


	/** BP delegate called when any requested initialization request completes */

	/** 当任意请求的初始化请求完成时的蓝图代理。 */
	UPROPERTY(BlueprintAssignable, Category = CommonUser)
	FCommonUserOnInitializeCompleteMulticast OnUserInitializeComplete;

	/** BP delegate called when the system sends an error/warning message */

	/** 当系统发送一个错误或警告消息时的蓝图代理。 */
	UPROPERTY(BlueprintAssignable, Category = CommonUser)
	FCommonUserHandleSystemMessageDelegate OnHandleSystemMessage;

	/** BP delegate called when privilege availability changes for a user  */

	/** 当一个用户的权限可用性改变时的蓝图代理。 */
	UPROPERTY(BlueprintAssignable, Category = CommonUser)
	FCommonUserAvailabilityChangedDelegate OnUserPrivilegeChanged;

	/** Send a system message via OnHandleSystemMessage */

	/** 凭借OnHandleSystemMessage发送系统消息。 */
	UFUNCTION(BlueprintCallable, Category = CommonUser)
	virtual void SendSystemMessage(FGameplayTag MessageType, FText TitleText, FText BodyText);

	/** Sets the maximum number of local players, will not destroy existing ones */

	/** 设置本地玩家的最大数量，不会销毁已经存在的玩家。 */
	UFUNCTION(BlueprintCallable, Category = CommonUser)
	virtual void SetMaxLocalPlayers(int32 InMaxLocalPLayers);

	/** Gets the maximum number of local players */

	/** 获取本地玩家的最大数量。 */
	UFUNCTION(BlueprintPure, Category = CommonUser)
	int32 GetMaxLocalPlayers() const;

	/** Gets the current number of local players, will always be at least 1 */

	/** 获取当前本地玩家数量，经常至少是一个。 */
	UFUNCTION(BlueprintPure, Category = CommonUser)
	int32 GetNumLocalPlayers() const;

	/** Returns the state of initializing the specified local player */

	/** 返回特定本地玩家的初始化状态。 */
	UFUNCTION(BlueprintPure, Category = CommonUser)
	ECommonUserInitializationState GetLocalPlayerInitializationState(int32 LocalPlayerIndex) const;

	/** Returns the user info for a given local player index in game instance, 0 is always valid in a running game */

	/** 返回在游戏实例中的给定本地玩家索引的用户信息，0是经常存在的在运行游戏时。 */
	UFUNCTION(BlueprintCallable, BlueprintPure = False, Category = CommonUser)
	const UCommonUserInfo* GetUserInfoForLocalPlayerIndex(int32 LocalPlayerIndex) const;

	/** Deprecated, use PlatformUserId when available */

	/** 废弃的，当PlatformUserId可用时使用。 */
	UFUNCTION(BlueprintCallable, BlueprintPure = False, Category = CommonUser)
	const UCommonUserInfo* GetUserInfoForPlatformUserIndex(int32 PlatformUserIndex) const;

	/** Returns the primary user info for a given platform user index. Can return null */

	/** 返回对于给定平台用户索引的主用户信息，可以返回空。 */
	UFUNCTION(BlueprintCallable, BlueprintPure = False, Category = CommonUser)
	const UCommonUserInfo* GetUserInfoForPlatformUser(FPlatformUserId PlatformUser) const;

	/** Returns the user info for a unique net id. Can return null */

	/** 返回对于唯一网络ID的用户信息，能返回空。 */
	UFUNCTION(BlueprintCallable, BlueprintPure = False, Category = CommonUser)
	const UCommonUserInfo* GetUserInfoForUniqueNetId(const FUniqueNetIdRepl& NetId) const;

	/** Deprecated, use InputDeviceId when available */

	/** 废弃的，当InputDeviceId可用时使用InputDeviceId。 */
	UFUNCTION(BlueprintCallable, BlueprintPure = False, Category = CommonUser)
	const UCommonUserInfo* GetUserInfoForControllerId(int32 ControllerId) const;

	/** Returns the user info for a given input device. Can return null */

	/** 返回对于给定输入设备的用户信息，能返回空。 */
	UFUNCTION(BlueprintCallable, BlueprintPure = False, Category = CommonUser)
	const UCommonUserInfo* GetUserInfoForInputDevice(FInputDeviceId InputDevice) const;

	/**
	 * Tries to start the process of creating or updating a local player, including logging in and creating a player controller.
	 * When the process has succeeded or failed, it will broadcast the OnUserInitializeComplete delegate.
	 *
	 * @param LocalPlayerIndex	Desired index of LocalPlayer in Game Instance, 0 will be primary player and 1+ for local multiplayer
	 * @param PrimaryInputDevice The physical controller that should be mapped to this user, will use the default device if invalid
	 * @param bCanUseGuestLogin	If true, this player can be a guest without a real Unique Net Id
	 *
	 * @returns true if the process was started, false if it failed before properly starting
	 */

	/**
	 * 尝试开启一个创造或更新本地玩家的进程，包括登录和创造玩家控制器。
	 * 当进程成功或失败时，它将会广播OnUserInitializeComplete代理。
	 *
	 * @param LocalPlayerIndex 渴望在游戏实例中的玩家索引，0将是主玩家，索引1+是针对本地多玩家情况。
	 * @param PrimaryInputDevice 映射到用户的物理控制器，如果不存在将会使用默认设备。
	 * @param bCanUseGuestLogin 如果True，玩家能够游客登录能够没有真实的唯一网络ID。
	 *
	 * @returns 如果进程开始则为True，如果在准备开始前就失败了，则为False。
	 */
	UFUNCTION(BlueprintCallable, Category = CommonUser)
	virtual bool TryToInitializeForLocalPlay(int32 LocalPlayerIndex, FInputDeviceId PrimaryInputDevice, bool bCanUseGuestLogin);

	/**
	 * Starts the process of taking a locally logged in user and doing a full online login including account permission checks.
	 * When the process has succeeded or failed, it will broadcast the OnUserInitializeComplete delegate.
	 *
	 * @param LocalPlayerIndex	Index of existing LocalPlayer in Game Instance
	 *
	 * @returns true if the process was started, false if it failed before properly starting
	 */

	/**
	 * 启动对本地已登录用户进行完整在线登录的流程，该流程包括账户权限检查。
	 * 当进程成功或失败时，将会广播OnUserInitializeComplete代理。
	 *
	 * @param LocalPlayerIndex 在游戏实例中存在的本地玩家的索引。
	 *
	 * @returns 如果进程开始则为True，如果在准备开始前就失败了，则为False。
	 */
	UFUNCTION(BlueprintCallable, Category = CommonUser)
	virtual bool TryToLoginForOnlinePlay(int32 LocalPlayerIndex);

	/**
	 * Starts a general user login and initialization process, using the params structure to determine what to log in to.
	 * When the process has succeeded or failed, it will broadcast the OnUserInitializeComplete delegate.
	 * AsyncAction_CommonUserInitialize provides several wrapper functions for using this in an Event graph.
	 *
	 * @returns true if the process was started, false if it failed before properly starting
	 */

	/**
	 * 开始一个普通用户登录和初始化进程，使用结构体参数去确定登录那个用户。
	 * 当进程成功或失败时，将会广播OnUserInitializeComplete代理。
	 * AsyncAction_CommonUserInitialize提供了在EventGraph中使用的几个封装函数。
	 *
	 * @returns 如果进程开始则为True，如果在准备开始前就失败了，则为False。
	 */
	UFUNCTION(BlueprintCallable, Category = CommonUser)
	virtual bool TryToInitializeUser(FCommonUserInitializeParams Params);

	/** 
	 * Starts the process of listening for user input for new and existing controllers and logging them.
	 * This will insert a key input handler on the active GameViewportClient and is turned off by calling again with empty key arrays.
	 *
	 * @param AnyUserKeys		Listen for these keys for any user, even the default user. Set this for an initial press start screen or empty to disable
	 * @param NewUserKeys		Listen for these keys for a new user without a player controller. Set this for splitscreen/local multiplayer or empty to disable
	 * @param Params			Params passed to TryToInitializeUser after detecting key input
	 */

	/**
	 * 对于新的和存在的控制器的用户输入开启一个监听进程，并且记录输入流程。
	 * 在激活的GameViewportClient会插入一个键输入处理器并且通过再次调用传入空的键数组来将其关闭。
	 *
	 * @param AnyUserKeys 对于任意用户监听的键数组，即使是默认用户。对于初始按压开始屏幕设置此项或设置为空以禁止。
	 * @param NewUserKeys 对于不带玩家控制器的新用户监听的键数组。对于分屏或本地多玩家设置此项或设置为空去禁止。
	 * @param Params 在键输入之后去TryToInitializeUser的参数。
	 */
	UFUNCTION(BlueprintCallable, Category = CommonUser)
	virtual void ListenForLoginKeyInput(TArray<FKey> AnyUserKeys, TArray<FKey> NewUserKeys, FCommonUserInitializeParams Params);

	/** Attempts to cancel an in-progress initialization attempt, this may not work on all platforms but will disable callbacks */

	/** 尝试去取消一个正在尝试初始化的进程，这也许不会在所有平台调用但将会禁止回调。 */
	UFUNCTION(BlueprintCallable, Category = CommonUser)
	virtual bool CancelUserInitialization(int32 LocalPlayerIndex);

	/** Logs a player out of any online systems, and optionally destroys the player entirely if it's not the first one */

	/** 一个玩家登出任意的在线系统，并且如果该玩家不是第一个玩家，则可选择性完全销毁这个玩家。 */
	UFUNCTION(BlueprintCallable, Category = CommonUser)
	virtual bool TryToLogOutUser(int32 LocalPlayerIndex, bool bDestroyPlayer = false);

	/** Resets the login and initialization state when returning to the main menu after an error */

	/** 当在错误之后返回主菜单时重置登录和初始化状态。 */
	UFUNCTION(BlueprintCallable, Category = CommonUser)
	virtual void ResetUserState();

	/** Returns true if this this could be a real platform user with a valid identity (even if not currently logged in)  */

	/** 如果这是一个带有有效认证的真实平台用户(即使当前没有登录)，则返回True。 */
	virtual bool IsRealPlatformUserIndex(int32 PlatformUserIndex) const;

	/** Returns true if this this could be a real platform user with a valid identity (even if not currently logged in) */

	/** 如果这是一个带有有效认证的真实平台用户(即使当前没有登录)，则返回True。 */
	virtual bool IsRealPlatformUser(FPlatformUserId PlatformUser) const;

	/** Converts index to id */

	/** 转换索引到ID。 */
	virtual FPlatformUserId GetPlatformUserIdForIndex(int32 PlatformUserIndex) const;

	/** Converts id to index */
	/** 转换ID到索引。 */
	virtual int32 GetPlatformUserIndexForId(FPlatformUserId PlatformUser) const;

	/** Gets the user for an input device */

	/** 从输入设备获取用户。 */
	virtual FPlatformUserId GetPlatformUserIdForInputDevice(FInputDeviceId InputDevice) const;

	/** Gets a user's primary input device id */

	/** 获取用户的主输入设备ID。 */
	virtual FInputDeviceId GetPrimaryInputDeviceForPlatformUser(FPlatformUserId PlatformUser) const;

	/** Call from game code to set the cached trait tags when platform state or options changes */

	/** 当平台状态或配置改变时，调用从游戏代码设置缓存特征标签。 */
	virtual void SetTraitTags(const FGameplayTagContainer& InTags);

	/** Gets the current tags that affect feature availability */

	/** 获取当前的有效可用性的标签。 */
	const FGameplayTagContainer& GetTraitTags() const { return CachedTraitTags; }

	/** Checks if a specific platform/feature tag is enabled */

	/** 检查一个特定平台或功能标签是否可用。 */
	UFUNCTION(BlueprintPure, Category=CommonUser)
	bool HasTraitTag(const FGameplayTag TraitTag) const { return CachedTraitTags.HasTag(TraitTag); }

	/** Checks to see if we should display a press start/input confirmation screen at startup. Games can call this or check the trait tags directly */

	/** 检查我们是否应该展示一个按下开始键或输入确认屏幕在启动时。游戏能够调用它或直接地检查特征标签。 */
	UFUNCTION(BlueprintPure, BlueprintPure, Category=CommonUser)
	virtual bool ShouldWaitForStartInput() const;


	// Functions for accessing low-level online system information

	// 用于访问底层在线系统信息的函数。

#if COMMONUSER_OSSV1
	/** Returns OSS interface of specific type, will return null if there is no type */

	/** 返回具体类型的OSS接口，如果类型不存在将会返回NULL。 */
	IOnlineSubsystem* GetOnlineSubsystem(ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;

	/** Returns identity interface of specific type, will return null if there is no type */

	/** 返回具体类型的认证接口，如果类型不存在将会返回NULL。 */
	IOnlineIdentity* GetOnlineIdentity(ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;

	/** Returns human readable name of OSS system */

	/** 返回人类可读的的OSS名称。 */
	FName GetOnlineSubsystemName(ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;

	/** Returns the current online connection status */

	/** 返回当前在线连接状态。 */
	EOnlineServerConnectionStatus::Type GetConnectionStatus(ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;
#else
	/** Get the services provider type, or None if there isn't one. */
	UE::Online::EOnlineServices GetOnlineServicesProvider(ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;
	
	/** Returns auth interface of specific type, will return null if there is no type */
	UE::Online::IAuthPtr GetOnlineAuth(ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;

	/** Returns the current online connection status */
	UE::Online::EOnlineServicesConnectionStatus GetConnectionStatus(ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;
#endif

	/** Returns true if we are currently connected to backend servers */

	/** 如果我们当前已经连接后台服务器，则返回True。 */
	bool HasOnlineConnection(ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;

	/** Returns the current login status for a player on the specified online system, only works for real platform users */

	/** 对于在具体在线系统的玩家返回当前登录状态，仅适用于真实平台用户们。 */
	ELoginStatusType GetLocalUserLoginStatus(FPlatformUserId PlatformUser, ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;

	/** Returns the unique net id for a local platform user */

	/** 对于本地平台用户返回唯一网络ID。 */
	FUniqueNetIdRepl GetLocalUserNetId(FPlatformUserId PlatformUser, ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;

	/** Convert a user id to a debug string */

	/** 转换用户ID到调试字符串。 */
	FString PlatformUserIdToString(FPlatformUserId UserId);

	/** Convert a context to a debug string */

	/** 转换上下文到调试字符串。 */
	FString ECommonUserOnlineContextToString(ECommonUserOnlineContext Context);

	/** Returns human readable string for privilege checks */

	/** 返回权限检查的人类可读字符串。 */
	virtual FText GetPrivilegeDescription(ECommonUserPrivilege Privilege) const;
	virtual FText GetPrivilegeResultDescription(ECommonUserPrivilegeResult Result) const;

	/** 
	 * Starts the process of login for an existing local user, will return false if callback was not scheduled 
	 * This activates the low level state machine and does not modify the initialization state on user info
	 */

	/**
	 * 为存在的本地用户开启登录进程，如果没有提前绑定将返回False。
	 * 这会激活底层状态机并且修改用户信息的初始化状态。
	 */
	DECLARE_DELEGATE_FiveParams(FOnLocalUserLoginCompleteDelegate, const UCommonUserInfo* /*UserInfo*/, ELoginStatusType /*NewStatus*/, FUniqueNetIdRepl /*NetId*/, const TOptional<FOnlineErrorType>& /*Error*/, ECommonUserOnlineContext /*Type*/);
	virtual bool LoginLocalUser(const UCommonUserInfo* UserInfo, ECommonUserPrivilege RequestedPrivilege, ECommonUserOnlineContext Context, FOnLocalUserLoginCompleteDelegate OnComplete);

	/** Assign a local player to a specific local user and call callbacks as needed */

	/** 分配一个本地玩家到具体本地用户并且如果需要将会调用回调。 */
	virtual void SetLocalPlayerUserInfo(ULocalPlayer* LocalPlayer, const UCommonUserInfo* UserInfo);

	/** Resolves a context that has default behavior into a specific context */

	/** 解决默认行为的上下文内容到具体上下文内容。 */
	ECommonUserOnlineContext ResolveOnlineContext(ECommonUserOnlineContext Context) const;

	/** True if there is a separate platform and service interface */

	/** 如果平台和服务解决是分开的，则返回True。 */
	bool HasSeparatePlatformContext() const;

protected:
	/** Internal structure that caches status and pointers for each online context */

	/** 每个在线系统上下文的内存状态和指针的内部结构体。 */
	struct FOnlineContextCache
	{
#if COMMONUSER_OSSV1
		/** Pointer to base subsystem, will stay valid as long as game instance does */

		/** 基本子系统指针，只要游戏实例一直有效，该指针就会一直有效。 */
		IOnlineSubsystem* OnlineSubsystem = nullptr;

		/** Cached identity system, this will always be valid */

		/** 缓存认证系统，这将会经常有效。 */
		IOnlineIdentityPtr IdentityInterface;

		/** Last connection status that was passed into the HandleNetworkConnectionStatusChanged hander */

		/** 上次HandleNetworkConnectionStatusChanged处理的最后连接状态。 */
		EOnlineServerConnectionStatus::Type	CurrentConnectionStatus = EOnlineServerConnectionStatus::Normal;
#else
		/** Online services, accessor to specific services */
		UE::Online::IOnlineServicesPtr OnlineServices;
		/** Cached auth service */
		UE::Online::IAuthPtr AuthService;
		/** Login status changed event handle */
		UE::Online::FOnlineEventDelegateHandle LoginStatusChangedHandle;
		/** Connection status changed event handle */
		UE::Online::FOnlineEventDelegateHandle ConnectionStatusChangedHandle;
		/** Last connection status that was passed into the HandleNetworkConnectionStatusChanged hander */
		UE::Online::EOnlineServicesConnectionStatus CurrentConnectionStatus = UE::Online::EOnlineServicesConnectionStatus::NotConnected;
#endif

		/** Resets state, important to clear all shared ptrs */

		/** 重置状态，重要的去清空所有共享指针。 */
		void Reset()
		{
#if COMMONUSER_OSSV1
			OnlineSubsystem = nullptr;
			IdentityInterface.Reset();
			CurrentConnectionStatus = EOnlineServerConnectionStatus::Normal;
#else
			OnlineServices.Reset();
			AuthService.Reset();
			CurrentConnectionStatus = UE::Online::EOnlineServicesConnectionStatus::NotConnected;
#endif
		}
	};

	/**
	 * Derive your class from TSharedFromThis to enable access to a TSharedRef directly from an object
	 * instance that's already been allocated.  Use the optional Mode template argument for thread-safety.
	 */

	/**
	* TSharedFromThis<T>: 
	 * 从TSharedFromThis孵化类到能够从已经分配的对象实例中直接地链接TSharedRef。
	 * NOTE: 使用方法TSharedRef<FUserLoginRequest> Request。
	 */

	/** Internal structure to represent an in-progress login request */

	/** 代表登录请求进程中的内部结构体。 */
	struct FUserLoginRequest : public TSharedFromThis<FUserLoginRequest>
	{
		FUserLoginRequest(UCommonUserInfo* InUserInfo, ECommonUserPrivilege InPrivilege, ECommonUserOnlineContext InContext, FOnLocalUserLoginCompleteDelegate&& InDelegate)
			: UserInfo(TWeakObjectPtr<UCommonUserInfo>(InUserInfo))
			, DesiredPrivilege(InPrivilege)
			, DesiredContext(InContext)
			, Delegate(MoveTemp(InDelegate))
			{}

		/** Which local user is trying to log on */

		/** 那个本地用户尝试去登录。 */
		TWeakObjectPtr<UCommonUserInfo> UserInfo;

		/** Overall state of login request, could come from many sources */

		/** 总体登录请求状态，能够来自很多资源。 */
		ECommonUserAsyncTaskState OverallLoginState = ECommonUserAsyncTaskState::NotStarted;

		/** State of attempt to use platform auth. When started, this immediately transitions to Failed for OSSv1, as we do not support platform auth there. */

		/** 尝试去使用平台认证状态，当开始时，在OSSv1将会立即转换到失败，而且我们也不会支持平台认证。 */
		ECommonUserAsyncTaskState TransferPlatformAuthState = ECommonUserAsyncTaskState::NotStarted;

		/** State of attempt to use AutoLogin */

		/** 尝试去使用自动登录状态。 */
		ECommonUserAsyncTaskState AutoLoginState = ECommonUserAsyncTaskState::NotStarted;

		/** State of attempt to use external login UI */

		/** 尝试去使用外部登录UI状态。 */
		ECommonUserAsyncTaskState LoginUIState = ECommonUserAsyncTaskState::NotStarted;

		/** Final privilege to that is requested */

		/** 请求的最终权限。 */
		ECommonUserPrivilege DesiredPrivilege = ECommonUserPrivilege::Invalid_Count;

		/** State of attempt to request the relevant privilege */

		/** 尝试去请求关联的权限状态。 */
		ECommonUserAsyncTaskState PrivilegeCheckState = ECommonUserAsyncTaskState::NotStarted;

		/** The final context to log into */

		/** 登录之后的最终上下文。 */
		ECommonUserOnlineContext DesiredContext = ECommonUserOnlineContext::Invalid;

		/** What online system we are currently logging into */

		/** 我们当前登录的在线系统是哪个。 */
		ECommonUserOnlineContext CurrentContext = ECommonUserOnlineContext::Invalid;

		/** User callback for completion */

		/** 对于完成用户回调。 */
		FOnLocalUserLoginCompleteDelegate Delegate;

		/** Most recent/relevant error to display to user */

		/** 展示给用户的大部分当前或关联的错误。 */

		/**
		 * When we have an optional value IsSet() returns true, and GetValue() is meaningful.
		 * Otherwise GetValue() is not meaningful.
		 */

		/**
		 * 当我们有一个可选值时IsSet()是返回True，并且GetValue()是有意义的。否则GetValue()是没有意义的。
		 */
		TOptional<FOnlineErrorType> Error;
	};


	/** Create a new user info object */

	/** 创建一个新的用户信息对象。 */
	virtual UCommonUserInfo* CreateLocalUserInfo(int32 LocalPlayerIndex);

	/** Deconst wrapper for const getters */

	/** 针对const获取器解除const封装。 */
	FORCEINLINE UCommonUserInfo* ModifyInfo(const UCommonUserInfo* Info) { return const_cast<UCommonUserInfo*>(Info); }

	/** Refresh user info from OSS */

	/** 从OSS刷新用户信息。 */
	virtual void RefreshLocalUserInfo(UCommonUserInfo* UserInfo);

	/** Possibly send privilege availability notification, compares current value to cached old value */

	/** 尽可能发送权限可用性通知，当前值和老值进程对比。 */
	virtual void HandleChangedAvailability(UCommonUserInfo* UserInfo, ECommonUserPrivilege Privilege, ECommonUserAvailability OldAvailability);

	/** Updates the cached privilege on a user and notifies delegate */

	/** 在用户和通知代理上更新缓存权限。 */
	virtual void UpdateUserPrivilegeResult(UCommonUserInfo* UserInfo, ECommonUserPrivilege Privilege, ECommonUserPrivilegeResult Result, ECommonUserOnlineContext Context);

	/** Gets internal data for a type of online system, can return null for service */

	/** 对某类在线系统获取内部数据，对于服务能返回空。 */
	const FOnlineContextCache* GetContextCache(ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game) const;
	FOnlineContextCache* GetContextCache(ECommonUserOnlineContext Context = ECommonUserOnlineContext::Game);

	/** Create and set up system objects before delegates are bound */

	/** 在代理被绑定前创建和设置系统对象。 */
	virtual void CreateOnlineContexts();
	virtual void DestroyOnlineContexts();

	/** Bind online delegates */

	/** 绑定在线代理。 */
	virtual void BindOnlineDelegates();

	/** Forcibly logs out and deinitializes a single user */

	/** 强制登录并反初始化单个用户。 */
	virtual void LogOutLocalUser(FPlatformUserId PlatformUser);

	/** Performs the next step of a login request, which could include completing it. Returns true if it's done */

	/** 执行登录请求的下一步操作，这可能包含整个登录过程，如果完成则返回True。 */
	virtual void ProcessLoginRequest(TSharedRef<FUserLoginRequest> Request);

	/** Call login on OSS, with platform auth from the platform OSS. Return true if AutoLogin started */

	/** 在OSS上调用登录，携带从平台OSS的平台认证。如果自动登录开始则返回True。 */
	virtual bool TransferPlatformAuth(FOnlineContextCache* System, TSharedRef<FUserLoginRequest> Request, FPlatformUserId PlatformUser);

	/** Call AutoLogin on OSS. Return true if AutoLogin started. */

	/** OSS的自动登录调用。如果自动登录已经开始则返回True。 */
	virtual bool AutoLogin(FOnlineContextCache* System, TSharedRef<FUserLoginRequest> Request, FPlatformUserId PlatformUser);

	/** Call ShowLoginUI on OSS. Return true if ShowLoginUI started. */

	/** OSS的展示登录UI调用，如果展示登录UI开始则返回True。 */
	virtual bool ShowLoginUI(FOnlineContextCache* System, TSharedRef<FUserLoginRequest> Request, FPlatformUserId PlatformUser);

	/** Call QueryUserPrivilege on OSS. Return true if QueryUserPrivilege started. */

	/** 在OSS的请求用户权限调用。如果请求用户权限已开始则返回True。 */
	virtual bool QueryUserPrivilege(FOnlineContextCache* System, TSharedRef<FUserLoginRequest> Request, FPlatformUserId PlatformUser);

	/** OSS-specific functions */

	/** OSS的具体函数。 */
#if COMMONUSER_OSSV1
	virtual ECommonUserPrivilege ConvertOSSPrivilege(EUserPrivileges::Type Privilege) const;
	virtual EUserPrivileges::Type ConvertOSSPrivilege(ECommonUserPrivilege Privilege) const;
	virtual ECommonUserPrivilegeResult ConvertOSSPrivilegeResult(EUserPrivileges::Type Privilege, uint32 Results) const;

	void BindOnlineDelegatesOSSv1();
	bool AutoLoginOSSv1(FOnlineContextCache* System, TSharedRef<FUserLoginRequest> Request, FPlatformUserId PlatformUser);
	bool ShowLoginUIOSSv1(FOnlineContextCache* System, TSharedRef<FUserLoginRequest> Request, FPlatformUserId PlatformUser);
	bool QueryUserPrivilegeOSSv1(FOnlineContextCache* System, TSharedRef<FUserLoginRequest> Request, FPlatformUserId PlatformUser);
#else
	virtual ECommonUserPrivilege ConvertOnlineServicesPrivilege(UE::Online::EUserPrivileges Privilege) const;
	virtual UE::Online::EUserPrivileges ConvertOnlineServicesPrivilege(ECommonUserPrivilege Privilege) const;
	virtual ECommonUserPrivilegeResult ConvertOnlineServicesPrivilegeResult(UE::Online::EUserPrivileges Privilege, UE::Online::EPrivilegeResults Results) const;

	void BindOnlineDelegatesOSSv2();
	void CacheConnectionStatus(ECommonUserOnlineContext Context);
	bool TransferPlatformAuthOSSv2(FOnlineContextCache* System, TSharedRef<FUserLoginRequest> Request, FPlatformUserId PlatformUser);
	bool AutoLoginOSSv2(FOnlineContextCache* System, TSharedRef<FUserLoginRequest> Request, FPlatformUserId PlatformUser);
	bool ShowLoginUIOSSv2(FOnlineContextCache* System, TSharedRef<FUserLoginRequest> Request, FPlatformUserId PlatformUser);
	bool QueryUserPrivilegeOSSv2(FOnlineContextCache* System, TSharedRef<FUserLoginRequest> Request, FPlatformUserId PlatformUser);
	TSharedPtr<UE::Online::FAccountInfo> GetOnlineServiceAccountInfo(UE::Online::IAuthPtr AuthService, FPlatformUserId InUserId) const;
#endif

	/** Callbacks for OSS functions */

	/** OSS函数的回调。 */
#if COMMONUSER_OSSV1
	virtual void HandleIdentityLoginStatusChanged(int32 PlatformUserIndex, ELoginStatus::Type OldStatus, ELoginStatus::Type NewStatus, const FUniqueNetId& NewId, ECommonUserOnlineContext Context);
	virtual void HandleUserLoginCompleted(int32 PlatformUserIndex, bool bWasSuccessful, const FUniqueNetId& NetId, const FString& Error, ECommonUserOnlineContext Context);
	virtual void HandleControllerPairingChanged(int32 PlatformUserIndex, FControllerPairingChangedUserInfo PreviousUser, FControllerPairingChangedUserInfo NewUser);
	virtual void HandleNetworkConnectionStatusChanged(const FString& ServiceName, EOnlineServerConnectionStatus::Type LastConnectionStatus, EOnlineServerConnectionStatus::Type ConnectionStatus, ECommonUserOnlineContext Context);
	virtual void HandleOnLoginUIClosed(TSharedPtr<const FUniqueNetId> LoggedInNetId, const int PlatformUserIndex, const FOnlineError& Error, ECommonUserOnlineContext Context);
	virtual void HandleCheckPrivilegesComplete(const FUniqueNetId& UserId, EUserPrivileges::Type Privilege, uint32 PrivilegeResults, ECommonUserPrivilege RequestedPrivilege, TWeakObjectPtr<UCommonUserInfo> CommonUserInfo, ECommonUserOnlineContext Context);
#else
	virtual void HandleAuthLoginStatusChanged(const UE::Online::FAuthLoginStatusChanged& EventParameters, ECommonUserOnlineContext Context);
	virtual void HandleUserLoginCompletedV2(const UE::Online::TOnlineResult<UE::Online::FAuthLogin>& Result, FPlatformUserId PlatformUser, ECommonUserOnlineContext Context);
	virtual void HandleOnLoginUIClosedV2(const UE::Online::TOnlineResult<UE::Online::FExternalUIShowLoginUI>& Result, FPlatformUserId PlatformUser, ECommonUserOnlineContext Context);
	virtual void HandleNetworkConnectionStatusChanged(const UE::Online::FConnectionStatusChanged& EventParameters, ECommonUserOnlineContext Context);
	virtual void HandleCheckPrivilegesComplete(const UE::Online::TOnlineResult<UE::Online::FQueryUserPrivilege>& Result, TWeakObjectPtr<UCommonUserInfo> CommonUserInfo, UE::Online::EUserPrivileges DesiredPrivilege, ECommonUserOnlineContext Context);
#endif

	/**
	 * Callback for when an input device (i.e. a gamepad) has been connected or disconnected. 
	 */

	/**
	 * 当输入设备已经被连接或失联时回调。
	 */
	virtual void HandleInputDeviceConnectionChanged(EInputDeviceConnectionState NewConnectionState, FPlatformUserId PlatformUserId, FInputDeviceId InputDeviceId);

	virtual void HandleLoginForUserInitialize(const UCommonUserInfo* UserInfo, ELoginStatusType NewStatus, FUniqueNetIdRepl NetId, const TOptional<FOnlineErrorType>& Error, ECommonUserOnlineContext Context, FCommonUserInitializeParams Params);
	virtual void HandleUserInitializeFailed(FCommonUserInitializeParams Params, FText Error);
	virtual void HandleUserInitializeSucceeded(FCommonUserInitializeParams Params);

	/** Callback for handling press start/login logic */

	/** 用于处理按下开始键/登录逻辑的回调函数。 */
	virtual bool OverrideInputKeyForLogin(FInputKeyEventArgs& EventArgs);


	/** Previous override handler, will restore on cancel */

	/** 先前的覆盖处理程序，在取消操作时将会恢复。 */
	FOverrideInputKeyHandler WrappedInputKeyHandler;

	/** List of keys to listen for from any user */

	/** 监听从任意用户的键列表。 */
	TArray<FKey> LoginKeysForAnyUser;

	/** List of keys to listen for a new unmapped user */

	/** 监听一个新的未映射用户的键列表。 */
	TArray<FKey> LoginKeysForNewUser;

	/** Params to use for a key-triggered login */

	/** 用于按键触发登录的参数。 */
	FCommonUserInitializeParams ParamsForLoginKey;

	/** Maximum number of local players */

	/** 最大本地玩家数量。 */
	int32 MaxNumberOfLocalPlayers = 0;
	
	/** True if this is a dedicated server, which doesn't require a LocalPlayer */

	/** 如果是专用服务器则为True，专用服务器没有本地玩家。 */
	bool bIsDedicatedServer = false;

	/** List of current in progress login requests */

	/** 当前在登录请求中的列表。 */
	TArray<TSharedRef<FUserLoginRequest>> ActiveLoginRequests;

	/** Information about each local user, from local player index to user */

	/** 每个本地用户的信息，从本地玩家索引到用户的信息。 */
	UPROPERTY()
	TMap<int32, TObjectPtr<UCommonUserInfo>> LocalUserInfos;
	
	/** Cached platform/mode trait tags */

	/** 缓存平台或模式的特征标签。 */
	FGameplayTagContainer CachedTraitTags;

	/** Do not access this outside of initialization */

	/** 请勿在初始化过程之外访问此内容。 */
	FOnlineContextCache* DefaultContextInternal = nullptr;
	FOnlineContextCache* ServiceContextInternal = nullptr;
	FOnlineContextCache* PlatformContextInternal = nullptr;

	friend UCommonUserInfo;
};
